package com.mostsnails.common.base.utils.common;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * 时间工具类
 *
 * @Author MostSnails
 * @Version 1.0
 */
public class TimeUtils {
    /**
     * 转换格式1：通用转换格式：yyyy-MM-dd HH:mm:ss
     */
    public static final String YYYY_MM_DD_HH_MM_SS_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 转换格式2：年-月-日
     */
    public static final String YYYY_MMDD_PATTERN = "yyyy-MM-dd";

    /**
     * 转换格式3：时-分-秒
     */
    public static final String HH_MM_SS_PATTERN = "HH:mm:ss";

    //--------------------------LocalDate -----------------------------------------

    //获取当前日期
    public static LocalDate getNow() {
        return LocalDate.now();
    }

    //获取昨天日期
    public static LocalDate getYesterday() {
        return LocalDate.now().minusDays(1);
    }

    //获取本月第一天
    public static LocalDate firstYearDay() {
        LocalDate now = TimeUtils.getNow();
        return LocalDate.of(now.getYear(), now.getMonth(), 1);
    }

    //获取本月最后一天
    public static LocalDate lastYearDay() {
        LocalDate now = TimeUtils.getNow();
        return now.with(TemporalAdjusters.lastDayOfMonth());
    }

    //自定义日期
    public static LocalDate customLocalDate(int year, int month, int dayOfMonth) {
        return LocalDate.of(year, month, dayOfMonth);
    }

    /**
     * 日 加 x 天
     *
     * @param param     修改日期参数
     * @param daysToAdd 增加天数
     */
    public static LocalDate addDayLocalDate(LocalDate param, long daysToAdd) {
        return param.plusDays(daysToAdd);
    }

    // ------------------------- LocalTime -----------------------------------------
    //获取当前日期时间
    public static LocalDateTime getNowTime() {
        return LocalDateTime.now();
    }

    //获取昨天开始时间
    public static LocalDateTime getYesterTime() {
        return LocalDateTime.of(getYesterday(), LocalTime.MIN);
    }

    //获取本月第一天开始时间 00:00:00
    public static LocalDateTime startOfThisMonth() {
        return LocalDateTime.of(firstYearDay(), LocalTime.MIN);
    }

    //获取本月最后一天结束时间 23:59:59
    public static LocalDateTime lastOfThisMonth() {
        return LocalDateTime.of(lastYearDay(), LocalTime.MAX);
    }

    //自定义时间
    public static LocalDateTime customLocalDateTime(int year, int month, int dayOfMonth, int hour, int minute, int second) {
        return LocalDateTime.of(year, month, dayOfMonth, hour, minute, second);
    }

    // ----------------------- LocalDate、LocalDateTime -> String ------------------------

    /**
     * LocalDate -> String yyyy-MM-dd
     * LocalDate 转 yyyy-MM-dd
     *
     * @param param 参数
     */
    public static String localDateConverString(LocalDate param) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(YYYY_MMDD_PATTERN);
        return param.format(fmt);
    }

    /**
     * LocalDateTime -> String yyyy-MM-dd
     * LocalDateTime 转 yyyy-MM-dd
     *
     * @param param 参数
     */
    public static String localDateTimeConverString(LocalDateTime param) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS_PATTERN);
        return param.format(fmt);
    }


    //----------------------- String ->  LocalDate、LocalDateTime ---------------------------

    /**
     * String yyyy-MM-dd -> LocalDate
     * String 转 LocalDate
     *
     * @param param 参数
     */
    public static LocalDate stringConverLocalDate(String param) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(YYYY_MMDD_PATTERN);
        return LocalDate.parse(param, fmt);
    }

    /**
     * String yyyy-MM-dd HH:mm:ss -> LocalDateTime
     * String 转 LocalDateTime
     *
     * @param param 参数
     */
    public static LocalDateTime stringConverLocalDateTime(String param) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS_PATTERN);
        return LocalDateTime.parse(param, fmt);
    }

    //----------------------- Long -> LocalDate、LocalDateTime、String---------------------------

    /**
     * Long 时间戳 -> String yyyy-MM-dd HH:mm:ss
     * Long 时间戳 转 yyyy-MM-dd HH:mm:ss
     *
     * @param param 参数
     */
    public static String longConverString(Long param) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS_PATTERN);
        return fmt.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(param), ZoneId.systemDefault()));
    }

    /**
     * Long 时间戳 -> LocalDateTime
     * Long 时间戳 转 LocalDateTime
     *
     * @param param 参数
     */
    public static LocalDateTime longConverLocalDateTime(Long param) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(param), ZoneId.systemDefault());
    }

    /**
     * Long 时间戳 -> LocalDate
     * Long 时间戳 转 LocalDate
     *
     * @param param 参数
     */
    public static LocalDate longConverLocalDate(Long param) {
        return longConverLocalDateTime(param).toLocalDate();
    }

    //----------------------- Date -> LocalDate、LocalDateTime、String---------------------------

    /**
     * Date 日期 -> LocalDate
     * Date 日期 转 LocalDate
     *
     * @param param 参数
     */
    public static LocalDate dateConverLocalDate(Date param) {
        return LocalDateTime.ofInstant(param.toInstant(), ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * Date 日期 -> LocalDateTime
     * Date 日期 转 LocalDateTime
     *
     * @param param 参数
     */
    public static LocalDateTime dateConverLocalDateTime(Date param) {
        return LocalDateTime.ofInstant(param.toInstant(), ZoneId.systemDefault());
    }

    /**
     * Date 日期 -> String yyyy-MM-dd HH:mm:ss
     * Date 日期 转 String yyyy-MM-dd HH:mm:ss
     *
     * @param param 参数
     */
    public static String dateConverString(Date param) {
        return new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS_PATTERN).format(param);
    }

    //----------------------- LocalDate、LocalDateTime、Date -> Long---------------------------

    /**
     * LocalDate  -> Long 时间戳
     * LocalDate  转 Long 时间戳
     *
     * @param param 参数
     */
    public static Long localDateConverLong(LocalDate param) {
        return param.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * LocalDateTime  -> Long 时间戳
     * LocalDateTime  转 Long 时间戳
     *
     * @param param 参数
     */
    public static Long localDateTimeConverLong(LocalDateTime param) {
        return param.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * LocalDateTime  -> Long 时间戳
     * LocalDateTime  转 Long 时间戳
     *
     * @param param 参数
     */
    public static Long dateConverLong(Date param) {
        return param.getTime();
    }

    // ---------------------LocalDate - > LocalDateTime 、Date ---------------------------

    /**
     * LocalDate  -> LocalDate
     * LocalDate  转 LocalDate
     *
     * @param param 参数
     */
    public static LocalDateTime localDateConverLocalDateTime(LocalDate param) {
        return LocalDateTime.of(param, LocalTime.parse("00:00:00"));
    }

    /**
     * LocalDate  -> Date
     * LocalDate  转 Date
     *
     * @param param 参数
     */
    public static Date localDateConverDate(LocalDate param) {
        return Date.from(param.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    // ---------------------LocalDate - > LocalDateTime 、Date ---------------------------

    /**
     * LocalDateTime  -> LocalDate
     * LocalDateTime  转 LocalDate
     *
     * @param param 参数
     */
    public static LocalDate localDateTimeConverLocalDate(LocalDateTime param) {
        return param.toLocalDate();
    }

    /**
     * LocalDateTime  -> Date
     * LocalDateTime  转 Date
     *
     * @param param 参数
     */
    public static Date localDateTimeConverDate(LocalDateTime param) {
        return Date.from(param.atZone(ZoneId.systemDefault()).toInstant());
    }


    // --------------------- compare -----------------------------------------------

    /**
     * 验证给定日期是否在范围内
     *
     * @param start 给定起始日期范围
     * @param end   给定结束日期范围
     * @param param 待验证参数
     * @return true 在范围内 false 不在范围内
     */
    public static boolean isStartDateBetweenEndDate(LocalDate start, LocalDate end, LocalDate param) {
        return (param.isAfter(start) || param.equals(start)) && (param.isBefore(end) || param.equals(end));
    }

    /**
     * 验证给定时间是否在范围内
     *
     * @param start 给定起始时间范围
     * @param end   给定结束时间范围
     * @param param 待验证参数
     * @return true 在范围内 false 不在范围内
     */
    public static boolean isStartTimeBetweenEndTime(LocalDateTime start, LocalDateTime end, LocalDateTime param) {
        return (param.isAfter(start) || param.equals(start)) && (param.isBefore(end) || param.equals(end));
    }
}
